package com.xpalive.attach.aspect;

import com.xpalive.attach.dto.Attachment;
import com.xpalive.base.BaseEdit;
import com.xpalive.base.BaseEntity;
import com.xpalive.base.dto.result.RespResult;
import com.xpalive.commons.BizAssert;
import com.xpalive.exception.BizException;
import com.xpalive.utils.XCommonUtils;
import com.xpalive.utils.XEnumUtils;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;

/**
 * @auther xiongping
 * @date 2019/6/4
 */
@Aspect
@Configuration
@Slf4j
public class AttachParamsAspect {

    private static final String ANNO = "@AttachParamsEnable";
    private static final String ANNO_INTERFACE = "AttachParams";

    @Pointcut("@annotation(com.xpalive.attach.aspect.AttachParamsEnable)")
    public void annotationPointCut() {
    }

    @AfterReturning(value = "annotationPointCut()", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        AttachParamsEnable attAnnotation = method.getAnnotation(AttachParamsEnable.class);
        Class<? extends Enum<?>> typeEnum = attAnnotation.refTypeEnum();
        Enum<?>[] typeEnumArray = XEnumUtils.getEnumConstantsShared(typeEnum);
        List<String> typeEnumList = Arrays.stream(typeEnumArray).map(item -> item.name())
            .collect(Collectors.toList());
        if (attAnnotation.active()) {
            Long id;
            BizAssert.notNull(result, MessageFormat.format("使用{0}注解标注的方法需要有返回值", ANNO));
            Object methodResult;
            if (result instanceof RespResult) {
                methodResult = ((RespResult) result).getData();
            } else {
                methodResult = result;
            }

            if (methodResult instanceof BaseEntity) {
                id = XCommonUtils.getId((BaseEntity) result);
            } else if (methodResult instanceof BaseEdit) {
                id = XCommonUtils.getId((BaseEdit) result);
            } else {
                id = null;
            }

            Object[] args = joinPoint.getArgs();
            if (id == null) {
                log.error("使用{}}注解标注的方法[{}.{}]获取到的Id为null", ANNO,
                    method.getDeclaringClass().getName(), method.getName());
            }
            if (args == null) {
                log.error("使用{}注解标注的方法需要有至少一个参数", ANNO);
            }
            List<AttachParams> attachmentParamsList = Arrays.stream(args)
                .filter(item -> item instanceof AttachParams)
                .map(item -> (AttachParams) item).collect(Collectors.toList());
            if (attachmentParamsList.isEmpty()) {
                log.error("使用{}注解标注的方法需要有至少一个参数是{}的实现类", ANNO, ANNO_INTERFACE);
            }

            log.info("附件AOP拦截方法{}" + method.getName());
            for (AttachParams attachmentParams : attachmentParamsList) {
                List<Attachment> attachmentList = attachmentParams.getAttachmentList();
                if (attachmentList != null) {
                    log.info("附件AOP开始保存附件");
                    //findAttachById 找到id下的所有附件
                    List<Attachment> dbList = new ArrayList<>();
                    for (Attachment editAttachment : attachmentList) {
                        final Long editId = editAttachment.getId();
                        Attachment attachment;
                        if (editId != null) {
                            XCommonUtils.cleanId(editAttachment);
                        } else {
                            dbList.removeIf(entity -> entity.getId().equals(editId));
                            //attachment = findById(editId);
                        }
                        //copy(editAttachment -> attachment)
                        String refType = editAttachment.getRefType();
                        if (!typeEnumList.contains(refType) && attAnnotation.refTypeValid()) {
                            final String errorMsg = MessageFormat.format("附件类型不正确{0}", refType);
                            log.error(errorMsg);
                            throw new BizException(errorMsg);
                        }
                        //edit attachment
                    }
                    // delete dbList
                } else {
                    log.info("附件AOP未找到需要保存的附件");
                }
            }
        } else {
            log.info("{} active is false", ANNO);
        }
    }


}
